package com.lq.memo.service.impl;

import com.lq.email.entity.EmailEntity;
import com.lq.email.exception.MyException;
import com.lq.email.service.EmailService;
import com.lq.memo.config.ValidateCodeProperties;
import com.lq.memo.entity.EmailValidateCodeConstant;
import com.lq.memo.exception.ValidateCodeException;
import com.lq.memo.service.ValidateCodeService;
import com.lq.memo.service.redis.RedisService;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @ClassName ValidateCodeServiceImpl
 * @Description
 * @Author LQ
 * @Date 2021/11/27 19:06
 * @Version 1.0
 */
@Service
public class ValidateCodeServiceImpl implements ValidateCodeService {
    @Autowired
    private RedisService redisService;

    @Autowired
    ValidateCodeProperties codeProperties;

    @Autowired
    EmailService emailService;

    /**
     * 创建验证码
     *
     * @param request  因为前后端分离,不再基于session,我们需要客户端(浏览器)请求的时候,
     *                 携带一个key(按照某种算法随机生成的字符串,模拟jsessionid)来和验证码一一对应
     * @param response
     * @throws ValidateCodeException
     */
    public void create(HttpServletRequest request, HttpServletResponse response) throws ValidateCodeException, IOException {
        String key = request.getParameter("key");
        if (StringUtils.isBlank(key)) {
            throw new ValidateCodeException("验证码key不能为空");
        }
        setHeader(response, codeProperties.getType());

        Captcha captcha = createCaptcha(codeProperties);
        // 验证码写入redis,将常量类定义的验证码前缀加上key作为验证码的key
        redisService.set(EmailValidateCodeConstant.CODE_PREFIX + key, StringUtils.lowerCase(captcha.text()), codeProperties.getTime());
        captcha.out(response.getOutputStream());
    }

    @Override
    public String createValidateCode2Email(Map<String, Object> map) throws ValidateCodeException, MyException {
        String key = map.get("key") != null ? map.get("key").toString() : null;
        String userId = map.get("userId") != null ? map.get("userId").toString() : null;
        String email = map.get("email") != null ? map.get("email").toString() : null;
        String validateCode = this.createValidateCode(key);
        EmailEntity emailEntity = new EmailEntity();
        emailEntity.setSendTo(email);
        emailEntity.setUserId(userId);
        emailEntity.setSubject("邮箱验证码确认");
        emailEntity.setText("请输入验证码:" + validateCode + "  \n该验证码在5分钟内有效果!");
        emailService.sendEmail(emailEntity);
        return validateCode;
    }

    @Override
    public String createValidateCode(String key) throws ValidateCodeException {
        if (StringUtils.isBlank(key)) {
            throw new ValidateCodeException("验证码key不能为空");
        }
        Captcha captcha = createCaptcha(codeProperties);
        String code = StringUtils.lowerCase(captcha.text());
        redisService.set(EmailValidateCodeConstant.CODE_PREFIX + key, code, codeProperties.getTime());
        return code;
    }

    /**
     * 验证码验证
     *
     * @param key
     * @param value
     * @throws ValidateCodeException
     */
    public void check(String key, String value) throws ValidateCodeException {
        // 根据key从redis获取验证码
        Object codeInRedis = redisService.get(EmailValidateCodeConstant.CODE_PREFIX + key);
        if (StringUtils.isBlank(value)) {
            throw new ValidateCodeException("请输入验证码");
        }
        if (codeInRedis == null) {
            throw new ValidateCodeException("验证码已经过期");
        }
        if (!StringUtils.equalsIgnoreCase(value, String.valueOf(codeInRedis))) {
            throw new ValidateCodeException("验证码不正确");
        }
    }

    /**
     * 生成验证码
     * 根据配置设置验证码格式,长宽高等信息
     *
     * @param code 验证码配置信息
     * @return
     */
    private Captcha createCaptcha(ValidateCodeProperties code) {
        Captcha captcha = null;
        if (StringUtils.equalsIgnoreCase(code.getType(), EmailValidateCodeConstant.GIF)) {
            captcha = new GifCaptcha(code.getWidth(), code.getHeight(), code.getLength());
        } else {
            captcha = new SpecCaptcha(code.getWidth(), code.getHeight(), code.getLength());
        }
        captcha.setCharType(code.getCharType());
        return captcha;
    }

    /**
     * 设置请求头
     *
     * @param response
     * @param type
     */
    private void setHeader(HttpServletResponse response, String type) {
        if (StringUtils.equals(type, EmailValidateCodeConstant.GIF)) {
            response.setContentType(MediaType.IMAGE_GIF_VALUE);
        }
        if (StringUtils.equals(type, EmailValidateCodeConstant.PNG)) {
            response.setContentType(MediaType.IMAGE_PNG_VALUE);
        }
        response.setHeader(HttpHeaders.PRAGMA, "No-cache");
        response.setHeader(HttpHeaders.CACHE_CONTROL, "No-cache");
        response.setDateHeader(HttpHeaders.EXPIRES, 0L);
    }

}
